<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  
  <title>并发基石-AQS与Condition | Eetal&#39;s Blog</title>

  <!-- keywords -->
  

  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta name="description" content="欢迎查看Eetal的第十二篇博客–并发基石-AQS与Condition Condition在前面的博客JUC相关中，已经初略介绍了Condition接口，代表一个条件，可以阻塞、唤醒一个条件队列今天来具体讲讲其与AQS（AbstractQueueSynchronizer）的实现源码Condition中的加入条件队列，阻塞，唤醒等等操作都是由AbstractQueueSynchronizer或其子类">
<meta property="og:type" content="article">
<meta property="og:title" content="并发基石-AQS与Condition">
<meta property="og:url" content="http://eetal.gitee.io/blog/2019/03/26/并发基石-AQS与Condition/index.html">
<meta property="og:site_name" content="Eetal&#39;s Blog">
<meta property="og:description" content="欢迎查看Eetal的第十二篇博客–并发基石-AQS与Condition Condition在前面的博客JUC相关中，已经初略介绍了Condition接口，代表一个条件，可以阻塞、唤醒一个条件队列今天来具体讲讲其与AQS（AbstractQueueSynchronizer）的实现源码Condition中的加入条件队列，阻塞，唤醒等等操作都是由AbstractQueueSynchronizer或其子类">
<meta property="og:locale" content="default">
<meta property="og:updated_time" content="2019-03-26T07:07:51.654Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="并发基石-AQS与Condition">
<meta name="twitter:description" content="欢迎查看Eetal的第十二篇博客–并发基石-AQS与Condition Condition在前面的博客JUC相关中，已经初略介绍了Condition接口，代表一个条件，可以阻塞、唤醒一个条件队列今天来具体讲讲其与AQS（AbstractQueueSynchronizer）的实现源码Condition中的加入条件队列，阻塞，唤醒等等操作都是由AbstractQueueSynchronizer或其子类">
  
    <link rel="alternative" href="/atom.xml" title="Eetal&#39;s Blog" type="application/atom+xml">
  
  
    <link rel="icon" href="http://www.yangyitao.top/FiveChess/resource/ico/favicon.ico">
  
  <link rel="stylesheet" href="/blog/css/style.css">
  
  

  <script src="//cdn.bootcss.com/require.js/2.3.2/require.min.js"></script>
  <script src="//cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>

  
</head>
<body>
  <div id="container">
    <div id="particles-js"></div>
    <div class="left-col">
    <div class="overlay"></div>
<div class="intrude-less">
	<header id="header" class="inner">
		<a href="/" class="profilepic">
			
			<img lazy-src="/blog/images/head.jpg" class="js-avatar">
			
		</a>

		<hgroup>
		  <h1 class="header-author"><a href="/">Eetal</a></h1>
		</hgroup>

		
		<p class="header-subtitle">java coder</p>
		

		
			<div class="switch-btn">
				<div class="icon">
					<div class="icon-ctn">
						<div class="icon-wrap icon-house" data-idx="0">
							<div class="birdhouse"></div>
							<div class="birdhouse_holes"></div>
						</div>
						<div class="icon-wrap icon-ribbon hide" data-idx="1">
							<div class="ribbon"></div>
						</div>
						
						<div class="icon-wrap icon-link hide" data-idx="2">
							<div class="loopback_l"></div>
							<div class="loopback_r"></div>
						</div>
						
						
					</div>
					
				</div>
				<div class="tips-box hide">
					<div class="tips-arrow"></div>
					<ul class="tips-inner">
						<li>菜单</li>
						<li>标签</li>
						
						<li>友情链接</li>
						
						
					</ul>
				</div>
			</div>
		

		<div class="switch-area">
			<div class="switch-wrap">
				<section class="switch-part switch-part1">
					<nav class="header-menu">
						<ul>
						
							<li><a href="/blog/">Home</a></li>
				        
							<li><a href="/blog/archives">Archives</a></li>
				        
						</ul>
					</nav>
					<nav class="header-nav">
						<div class="social">
							
						</div>
					</nav>
				</section>
				
				
				<section class="switch-part switch-part2">
					<div class="widget tagcloud" id="js-tagcloud">
						
					</div>
				</section>
				
				
				
				<section class="switch-part switch-part3">
					<div id="js-friends">
					
			          <a target="_blank" class="main-nav-link switch-friends-link" href="https://github.com/smackgg/hexo-theme-smackdown">smackdown</a>
			        
			        </div>
				</section>
				

				
			</div>
		</div>
	</header>				
</div>
    </div>
    <div class="mid-col">
      <nav id="mobile-nav">
  	<div class="overlay">
  		<div class="slider-trigger"></div>
  		<h1 class="header-author js-mobile-header hide">Eetal</h1>
  	</div>
	<div class="intrude-less">
		<header id="header" class="inner">
			<div class="profilepic">
				<img lazy-src="/blog/images/head.jpg" class="js-avatar">
			</div>
			<hgroup>
			  <h1 class="header-author">Eetal</h1>
			</hgroup>
			
			<p class="header-subtitle">java coder</p>
			
			<nav class="header-menu">
				<ul>
				
					<li><a href="/blog/">Home</a></li>
		        
					<li><a href="/blog/archives">Archives</a></li>
		        
		        <div class="clearfix"></div>
				</ul>
			</nav>
			<nav class="header-nav">
				<div class="social">
					
				</div>
			</nav>
		</header>				
	</div>
</nav>
      <div class="body-wrap"><article id="post-并发基石-AQS与Condition" class="article article-type-post" itemscope itemprop="blogPost">
  
    <div class="article-meta">
      <a href="/blog/2019/03/26/并发基石-AQS与Condition/" class="article-date">
  	<time datetime="2019-03-26T00:28:37.930Z" itemprop="datePublished">2019-03-26</time>
</a>
    </div>
  
  <div class="article-inner">
    
      <input type="hidden" class="isFancy" />
    
    
      <header class="article-header">
        
  
    <h1 class="article-title" itemprop="name">
      并发基石-AQS与Condition
      
    </h1>
  

      </header>
      
      <div class="article-info article-info-post">
        
        

        
        <div class="clearfix"></div>
      </div>
      
    
    <div class="article-entry" itemprop="articleBody">
      
        <p>欢迎查看Eetal的第十二篇博客–并发基石-AQS与Condition</p>
<h2 id="Condition"><a href="#Condition" class="headerlink" title="Condition"></a>Condition</h2><p>在前面的博客JUC相关中，已经初略介绍了Condition接口，代表一个条件，可以阻塞、唤醒一个条件队列<br>今天来具体讲讲其与AQS（AbstractQueueSynchronizer）的实现源码<br>Condition中的加入条件队列，阻塞，唤醒等等操作都是由AbstractQueueSynchronizer或其子类方法完成</p>
<h2 id="AQS"><a href="#AQS" class="headerlink" title="AQS"></a>AQS</h2><p>AbstractQueueSynchronizer是java提供的队列同步器，个人理解更贴近一个线程调度的管理者<br>首先我们了解其内部类Node，Node既可以代表Condition的一个条件队列（单向链表），也可以代表当前锁资源的同步队列（双向链表）中的一个竞争线程的节点<br>先看其结构</p>
<h3 id="Node"><a href="#Node" class="headerlink" title="Node"></a>Node</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br></pre></td><td class="code"><pre><span class="line">static final class Node &#123;</span><br><span class="line">        /** Marker to indicate a node is waiting <span class="keyword">in</span> shared mode */</span><br><span class="line">        static final Node SHARED = new Node();</span><br><span class="line">        /** Marker to indicate a node is waiting <span class="keyword">in</span> exclusive mode */</span><br><span class="line">        static final Node EXCLUSIVE = null;</span><br><span class="line"></span><br><span class="line">        /** waitStatus value to indicate thread has cancelled */</span><br><span class="line">        static final int CANCELLED =  1;</span><br><span class="line">        /** waitStatus value to indicate successor<span class="string">'s thread needs unparking */</span></span><br><span class="line"><span class="string">        static final int SIGNAL    = -1;</span></span><br><span class="line"><span class="string">        /** waitStatus value to indicate thread is waiting on condition */</span></span><br><span class="line"><span class="string">        static final int CONDITION = -2;</span></span><br><span class="line"><span class="string">        /**</span></span><br><span class="line"><span class="string">         * waitStatus value to indicate the next acquireShared should</span></span><br><span class="line"><span class="string">         * unconditionally propagate</span></span><br><span class="line"><span class="string">         */</span></span><br><span class="line"><span class="string">        static final int PROPAGATE = -3;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">        /**</span></span><br><span class="line"><span class="string">         * Status field, taking on only the values:</span></span><br><span class="line"><span class="string">         *   SIGNAL:     The successor of this node is (or will soon be)</span></span><br><span class="line"><span class="string">         *               blocked (via park), so the current node must</span></span><br><span class="line"><span class="string">         *               unpark its successor when it releases or</span></span><br><span class="line"><span class="string">         *               cancels. To avoid races, acquire methods must</span></span><br><span class="line"><span class="string">         *               first indicate they need a signal,</span></span><br><span class="line"><span class="string">         *               then retry the atomic acquire, and then,</span></span><br><span class="line"><span class="string">         *               on failure, block.</span></span><br><span class="line"><span class="string">         *   CANCELLED:  This node is cancelled due to timeout or interrupt.</span></span><br><span class="line"><span class="string">         *               Nodes never leave this state. In particular,</span></span><br><span class="line"><span class="string">         *               a thread with cancelled node never again blocks.</span></span><br><span class="line"><span class="string">         *   CONDITION:  This node is currently on a condition queue.</span></span><br><span class="line"><span class="string">         *               It will not be used as a sync queue node</span></span><br><span class="line"><span class="string">         *               until transferred, at which time the status</span></span><br><span class="line"><span class="string">         *               will be set to 0. (Use of this value here has</span></span><br><span class="line"><span class="string">         *               nothing to do with the other uses of the</span></span><br><span class="line"><span class="string">         *               field, but simplifies mechanics.)</span></span><br><span class="line"><span class="string">         *   PROPAGATE:  A releaseShared should be propagated to other</span></span><br><span class="line"><span class="string">         *               nodes. This is set (for head node only) in</span></span><br><span class="line"><span class="string">         *               doReleaseShared to ensure propagation</span></span><br><span class="line"><span class="string">         *               continues, even if other operations have</span></span><br><span class="line"><span class="string">         *               since intervened.</span></span><br><span class="line"><span class="string">         *   0:          None of the above</span></span><br><span class="line"><span class="string">         *</span></span><br><span class="line"><span class="string">         * The values are arranged numerically to simplify use.</span></span><br><span class="line"><span class="string">         * Non-negative values mean that a node doesn'</span>t need to</span><br><span class="line">         * signal. So, most code doesn<span class="string">'t need to check for particular</span></span><br><span class="line"><span class="string">         * values, just for sign.</span></span><br><span class="line"><span class="string">         *</span></span><br><span class="line"><span class="string">         * The field is initialized to 0 for normal sync nodes, and</span></span><br><span class="line"><span class="string">         * CONDITION for condition nodes.  It is modified using CAS</span></span><br><span class="line"><span class="string">         * (or when possible, unconditional volatile writes).</span></span><br><span class="line"><span class="string">         */</span></span><br><span class="line"><span class="string">        volatile int waitStatus;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">        /**</span></span><br><span class="line"><span class="string">         * Link to predecessor node that current node/thread relies on</span></span><br><span class="line"><span class="string">         * for checking waitStatus. Assigned during enqueuing, and nulled</span></span><br><span class="line"><span class="string">         * out (for sake of GC) only upon dequeuing.  Also, upon</span></span><br><span class="line"><span class="string">         * cancellation of a predecessor, we short-circuit while</span></span><br><span class="line"><span class="string">         * finding a non-cancelled one, which will always exist</span></span><br><span class="line"><span class="string">         * because the head node is never cancelled: A node becomes</span></span><br><span class="line"><span class="string">         * head only as a result of successful acquire. A</span></span><br><span class="line"><span class="string">         * cancelled thread never succeeds in acquiring, and a thread only</span></span><br><span class="line"><span class="string">         * cancels itself, not any other node.</span></span><br><span class="line"><span class="string">         */</span></span><br><span class="line"><span class="string">        volatile Node prev;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">        /**</span></span><br><span class="line"><span class="string">         * Link to the successor node that the current node/thread</span></span><br><span class="line"><span class="string">         * unparks upon release. Assigned during enqueuing, adjusted</span></span><br><span class="line"><span class="string">         * when bypassing cancelled predecessors, and nulled out (for</span></span><br><span class="line"><span class="string">         * sake of GC) when dequeued.  The enq operation does not</span></span><br><span class="line"><span class="string">         * assign next field of a predecessor until after attachment,</span></span><br><span class="line"><span class="string">         * so seeing a null next field does not necessarily mean that</span></span><br><span class="line"><span class="string">         * node is at end of queue. However, if a next field appears</span></span><br><span class="line"><span class="string">         * to be null, we can scan prev'</span>s from the tail to</span><br><span class="line">         * double-check.  The next field of cancelled nodes is <span class="built_in">set</span> to</span><br><span class="line">         * point to the node itself instead of null, to make life</span><br><span class="line">         * easier <span class="keyword">for</span> isOnSyncQueue.</span><br><span class="line">         */</span><br><span class="line">        volatile Node next;</span><br><span class="line"></span><br><span class="line">        /**</span><br><span class="line">         * The thread that enqueued this node.  Initialized on</span><br><span class="line">         * construction and nulled out after use.</span><br><span class="line">         */</span><br><span class="line">        volatile Thread thread;</span><br><span class="line"></span><br><span class="line">        /**</span><br><span class="line">         * Link to next node waiting on condition, or the special</span><br><span class="line">         * value SHARED.  Because condition queues are accessed only</span><br><span class="line">         * when holding <span class="keyword">in</span> exclusive mode, we just need a simple</span><br><span class="line">         * linked queue to hold nodes <span class="keyword">while</span> they are waiting on</span><br><span class="line">         * conditions. They are <span class="keyword">then</span> transferred to the queue to</span><br><span class="line">         * re-acquire. And because conditions can only be exclusive,</span><br><span class="line">         * we save a field by using special value to indicate shared</span><br><span class="line">         * mode.</span><br><span class="line">         */</span><br><span class="line">        Node nextWaiter;</span><br><span class="line"></span><br><span class="line">        /**</span><br><span class="line">         * Returns <span class="literal">true</span> <span class="keyword">if</span> node is waiting <span class="keyword">in</span> shared mode.</span><br><span class="line">         */</span><br><span class="line">        final boolean <span class="function"><span class="title">isShared</span></span>() &#123;</span><br><span class="line">            <span class="built_in">return</span> nextWaiter == SHARED;</span><br><span class="line">        &#125;</span><br><span class="line">		...</span><br><span class="line">	&#125;</span><br></pre></td></tr></table></figure>
<p>Node中保存有竞争锁的线程对象<br>prev属性代表同步队列中的上一个节点<br>next属性代表同步队列中的下一个节点<br>nextWaiter属性，如果Node处于条件队列中，则nextWaiter指向条件队列中的下一个Node<br>nextWaiter属性，如果Node处于同步队列中，则nextWaiter代表同步模式，SHARE和EXCLUSIVE<br>因为条件队列中的都是互斥，所以不需要保存该mode</p>
<h3 id="执行开始"><a href="#执行开始" class="headerlink" title="执行开始"></a>执行开始</h3><p>首先Condition调用了await方法<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br></pre></td><td class="code"><pre><span class="line">final int fullyRelease(Node node) &#123;</span><br><span class="line">	boolean failed = <span class="literal">true</span>;</span><br><span class="line">	try &#123;</span><br><span class="line">		int savedState = getState();</span><br><span class="line">		<span class="keyword">if</span> (release(savedState)) &#123;</span><br><span class="line">			failed = <span class="literal">false</span>;</span><br><span class="line">			<span class="built_in">return</span> savedState;</span><br><span class="line">		&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">			throw new IllegalMonitorStateException();</span><br><span class="line">		&#125;</span><br><span class="line">	&#125; finally &#123;</span><br><span class="line">		<span class="keyword">if</span> (failed)</span><br><span class="line">			node.waitStatus = Node.CANCELLED;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"> public final void await() throws InterruptedException &#123;</span><br><span class="line">            <span class="keyword">if</span> (Thread.interrupted())</span><br><span class="line">                throw new InterruptedException();</span><br><span class="line">            Node node = addConditionWaiter();</span><br><span class="line">            int savedState = fullyRelease(node);</span><br><span class="line">            int interruptMode = 0;</span><br><span class="line">            <span class="keyword">while</span> (!isOnSyncQueue(node)) &#123;</span><br><span class="line">                LockSupport.park(this);</span><br><span class="line">                <span class="keyword">if</span> ((interruptMode = checkInterruptWhileWaiting(node)) != 0)</span><br><span class="line">                    <span class="built_in">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (acquireQueued(node, savedState) &amp;&amp; interruptMode != THROW_IE)</span><br><span class="line">                interruptMode = REINTERRUPT;</span><br><span class="line">            <span class="keyword">if</span> (node.nextWaiter != null) // clean up <span class="keyword">if</span> cancelled</span><br><span class="line">                unlinkCancelledWaiters();</span><br><span class="line">            <span class="keyword">if</span> (interruptMode != 0)</span><br><span class="line">                reportInterruptAfterWait(interruptMode);</span><br><span class="line">        &#125;</span><br><span class="line">final boolean acquireQueued(final Node node, int arg) &#123;</span><br><span class="line">        boolean failed = <span class="literal">true</span>;</span><br><span class="line">        try &#123;</span><br><span class="line">            boolean interrupted = <span class="literal">false</span>;</span><br><span class="line">            <span class="keyword">for</span> (;;) &#123;</span><br><span class="line">                final Node p = node.predecessor();</span><br><span class="line">                <span class="keyword">if</span> (p == head &amp;&amp; tryAcquire(arg)) &#123;</span><br><span class="line">                    setHead(node);</span><br><span class="line">                    p.next = null; // <span class="built_in">help</span> GC</span><br><span class="line">                    failed = <span class="literal">false</span>;</span><br><span class="line">                    <span class="built_in">return</span> interrupted;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">if</span> (shouldParkAfterFailedAcquire(p, node) &amp;&amp;</span><br><span class="line">                    parkAndCheckInterrupt())</span><br><span class="line">                    interrupted = <span class="literal">true</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; finally &#123;</span><br><span class="line">            <span class="keyword">if</span> (failed)</span><br><span class="line">                cancelAcquire(node);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">	 private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) &#123;</span><br><span class="line">        int ws = pred.waitStatus;</span><br><span class="line">        <span class="keyword">if</span> (ws == Node.SIGNAL)</span><br><span class="line">            /*</span><br><span class="line">             * This node has already <span class="built_in">set</span> status asking a release</span><br><span class="line">             * to signal it, so it can safely park.</span><br><span class="line">             */</span><br><span class="line">            <span class="built_in">return</span> <span class="literal">true</span>;</span><br><span class="line">        <span class="keyword">if</span> (ws &gt; 0) &#123;</span><br><span class="line">            /*</span><br><span class="line">             * Predecessor was cancelled. Skip over predecessors and</span><br><span class="line">             * indicate retry.</span><br><span class="line">             */</span><br><span class="line">            <span class="keyword">do</span> &#123;</span><br><span class="line">                node.prev = pred = pred.prev;</span><br><span class="line">            &#125; <span class="keyword">while</span> (pred.waitStatus &gt; 0);</span><br><span class="line">            pred.next = node;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            /*</span><br><span class="line">             * waitStatus must be 0 or PROPAGATE.  Indicate that we</span><br><span class="line">             * need a signal, but don<span class="string">'t park yet.  Caller will need to</span></span><br><span class="line"><span class="string">             * retry to make sure it cannot acquire before parking.</span></span><br><span class="line"><span class="string">             */</span></span><br><span class="line"><span class="string">            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);</span></span><br><span class="line"><span class="string">        &#125;</span></span><br><span class="line"><span class="string">        return false;</span></span><br><span class="line"><span class="string">    &#125;</span></span><br><span class="line"><span class="string">	private Node addConditionWaiter() &#123;</span></span><br><span class="line"><span class="string">	Node t = lastWaiter;</span></span><br><span class="line"><span class="string">	// If lastWaiter is cancelled, clean out.</span></span><br><span class="line"><span class="string">	if (t != null &amp;&amp; t.waitStatus != Node.CONDITION) &#123;</span></span><br><span class="line"><span class="string">		unlinkCancelledWaiters();</span></span><br><span class="line"><span class="string">		t = lastWaiter;</span></span><br><span class="line"><span class="string">	&#125;</span></span><br><span class="line"><span class="string">	Node node = new Node(Thread.currentThread(), Node.CONDITION);</span></span><br><span class="line"><span class="string">	if (t == null)</span></span><br><span class="line"><span class="string">		firstWaiter = node;</span></span><br><span class="line"><span class="string">	else</span></span><br><span class="line"><span class="string">		t.nextWaiter = node;</span></span><br><span class="line"><span class="string">	lastWaiter = node;</span></span><br><span class="line"><span class="string">	return node;</span></span><br><span class="line"><span class="string">	&#125;</span></span><br><span class="line"><span class="string">	private void unlinkCancelledWaiters() &#123;</span></span><br><span class="line"><span class="string">	Node t = firstWaiter;</span></span><br><span class="line"><span class="string">	Node trail = null;</span></span><br><span class="line"><span class="string">	while (t != null) &#123;</span></span><br><span class="line"><span class="string">		Node next = t.nextWaiter;</span></span><br><span class="line"><span class="string">		if (t.waitStatus != Node.CONDITION) &#123;</span></span><br><span class="line"><span class="string">			t.nextWaiter = null;</span></span><br><span class="line"><span class="string">			if (trail == null)</span></span><br><span class="line"><span class="string">				firstWaiter = next;</span></span><br><span class="line"><span class="string">			else</span></span><br><span class="line"><span class="string">				trail.nextWaiter = next;</span></span><br><span class="line"><span class="string">			if (next == null)</span></span><br><span class="line"><span class="string">				lastWaiter = trail;</span></span><br><span class="line"><span class="string">		&#125;</span></span><br><span class="line"><span class="string">		else</span></span><br><span class="line"><span class="string">			trail = t;</span></span><br><span class="line"><span class="string">		t = next;</span></span><br><span class="line"><span class="string">	&#125;</span></span><br><span class="line"><span class="string">&#125;</span></span><br></pre></td></tr></table></figure></p>
<p>简单捋一下await的逻辑，首先创建一个Node到等待队列里，然后释放资源<br>接着不断循环判断是否已经在同步队列里了，不在则挂起线程直到被UnPark<br>当处于同步队列里且被唤醒后就会调用请求资源的方法<br>不断的自旋尝试获取锁，如果处于头节点则获取得到资源，恢复执行后续代码<br>如果他不是同步队列的头节点，则判断他在同步队列里的前驱节点<br>如果前驱节点也处于请求释放的状态，因为总是唤醒前面的节点，所以这个节点这时候就可以安全的挂起<br>如果前驱节点处于取消状态，则不断清理被前驱取消的节点，直到第一个处于非取消状态的节点，将该节点作为当前结点的前驱<br>剩下的waitstatus中-2代表在条件队列已经不需要考虑，只剩下0（初始状态需要请求）和-3（读写锁的读锁请求到共享资源时，标记为该状态代表可以执行）<br>就把前驱节点更改为请求释放signal的状态<br>最后把所有已经不是条件等待状态的node移出队列</p>
<p>如果调用了signal方法<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br></pre></td><td class="code"><pre><span class="line">public final void <span class="function"><span class="title">signal</span></span>() &#123;</span><br><span class="line">            <span class="keyword">if</span> (!isHeldExclusively())</span><br><span class="line">                throw new IllegalMonitorStateException();</span><br><span class="line">            Node first = firstWaiter;</span><br><span class="line">            <span class="keyword">if</span> (first != null)</span><br><span class="line">                doSignal(first);</span><br><span class="line">        &#125;</span><br><span class="line">private void doSignal(Node first) &#123;</span><br><span class="line">	<span class="keyword">do</span> &#123;</span><br><span class="line">		<span class="keyword">if</span> ( (firstWaiter = first.nextWaiter) == null)</span><br><span class="line">			lastWaiter = null;</span><br><span class="line">		first.nextWaiter = null;</span><br><span class="line">	&#125; <span class="keyword">while</span> (!transferForSignal(first) &amp;&amp;</span><br><span class="line">			 (first = firstWaiter) != null);</span><br><span class="line">&#125;    </span><br><span class="line">final boolean transferForSignal(Node node) &#123;</span><br><span class="line">        /*</span><br><span class="line">         * If cannot change waitStatus, the node has been cancelled.</span><br><span class="line">         */</span><br><span class="line">        <span class="keyword">if</span> (!compareAndSetWaitStatus(node, Node.CONDITION, 0))</span><br><span class="line">            <span class="built_in">return</span> <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line">        /*</span><br><span class="line">         * Splice onto queue and try to <span class="built_in">set</span> waitStatus of predecessor to</span><br><span class="line">         * indicate that thread is (probably) waiting. If cancelled or</span><br><span class="line">         * attempt to <span class="built_in">set</span> waitStatus fails, wake up to resync (<span class="keyword">in</span> <span class="built_in">which</span></span><br><span class="line">         * <span class="keyword">case</span> the waitStatus can be transiently and harmlessly wrong).</span><br><span class="line">         */</span><br><span class="line">        Node p = enq(node);</span><br><span class="line">        int ws = p.waitStatus;</span><br><span class="line">        <span class="keyword">if</span> (ws &gt; 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))</span><br><span class="line">            LockSupport.unpark(node.thread);</span><br><span class="line">        <span class="built_in">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">private Node enq(final Node node) &#123;</span><br><span class="line">        <span class="keyword">for</span> (;;) &#123;</span><br><span class="line">            Node t = tail;</span><br><span class="line">            <span class="keyword">if</span> (t == null) &#123; // Must initialize</span><br><span class="line">                <span class="keyword">if</span> (compareAndSetHead(new Node()))</span><br><span class="line">                    tail = head;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                node.prev = t;</span><br><span class="line">                <span class="keyword">if</span> (compareAndSetTail(t, node)) &#123;</span><br><span class="line">                    t.next = node;</span><br><span class="line">                    <span class="built_in">return</span> t;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"> public final void await() throws InterruptedException &#123;</span><br><span class="line">            <span class="keyword">if</span> (Thread.interrupted())</span><br><span class="line">                throw new InterruptedException();</span><br><span class="line">            Node node = addConditionWaiter();</span><br><span class="line">            int savedState = fullyRelease(node);</span><br><span class="line">            int interruptMode = 0;</span><br><span class="line">            <span class="keyword">while</span> (!isOnSyncQueue(node)) &#123;</span><br><span class="line">                LockSupport.park(this);</span><br><span class="line">                <span class="keyword">if</span> ((interruptMode = checkInterruptWhileWaiting(node)) != 0)</span><br><span class="line">                    <span class="built_in">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (acquireQueued(node, savedState) &amp;&amp; interruptMode != THROW_IE)</span><br><span class="line">                interruptMode = REINTERRUPT;</span><br><span class="line">            <span class="keyword">if</span> (node.nextWaiter != null) // clean up <span class="keyword">if</span> cancelled</span><br><span class="line">                unlinkCancelledWaiters();</span><br><span class="line">            <span class="keyword">if</span> (interruptMode != 0)</span><br><span class="line">                reportInterruptAfterWait(interruptMode);</span><br><span class="line">        &#125;</span><br><span class="line">final int fullyRelease(Node node) &#123;</span><br><span class="line">	boolean failed = <span class="literal">true</span>;</span><br><span class="line">	try &#123;</span><br><span class="line">		int savedState = getState();</span><br><span class="line">		<span class="keyword">if</span> (release(savedState)) &#123;</span><br><span class="line">			failed = <span class="literal">false</span>;</span><br><span class="line">			<span class="built_in">return</span> savedState;</span><br><span class="line">		&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">			throw new IllegalMonitorStateException();</span><br><span class="line">		&#125;</span><br><span class="line">	&#125; finally &#123;</span><br><span class="line">		<span class="keyword">if</span> (failed)</span><br><span class="line">			node.waitStatus = Node.CANCELLED;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line">public final boolean release(int arg) &#123;</span><br><span class="line">        <span class="keyword">if</span> (tryRelease(arg)) &#123;</span><br><span class="line">            Node h = head;</span><br><span class="line">            <span class="keyword">if</span> (h != null &amp;&amp; h.waitStatus != 0)</span><br><span class="line">                unparkSuccessor(h);</span><br><span class="line">            <span class="built_in">return</span> <span class="literal">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="built_in">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">private void unparkSuccessor(Node node) &#123;</span><br><span class="line">	/*</span><br><span class="line">	 * If status is negative (i.e., possibly needing signal) try</span><br><span class="line">	 * to clear <span class="keyword">in</span> anticipation of signalling.  It is OK <span class="keyword">if</span> this</span><br><span class="line">	 * fails or <span class="keyword">if</span> status is changed by waiting thread.</span><br><span class="line">	 */</span><br><span class="line">	int ws = node.waitStatus;</span><br><span class="line">	<span class="keyword">if</span> (ws &lt; 0)</span><br><span class="line">		compareAndSetWaitStatus(node, ws, 0);</span><br><span class="line"></span><br><span class="line">	/*</span><br><span class="line">	 * Thread to unpark is held <span class="keyword">in</span> successor, <span class="built_in">which</span> is normally</span><br><span class="line">	 * just the next node.  But <span class="keyword">if</span> cancelled or apparently null,</span><br><span class="line">	 * traverse backwards from tail to find the actual</span><br><span class="line">	 * non-cancelled successor.</span><br><span class="line">	 */</span><br><span class="line">	Node s = node.next;</span><br><span class="line">	<span class="keyword">if</span> (s == null || s.waitStatus &gt; 0) &#123;</span><br><span class="line">		s = null;</span><br><span class="line">		<span class="keyword">for</span> (Node t = tail; t != null &amp;&amp; t != node; t = t.prev)</span><br><span class="line">			<span class="keyword">if</span> (t.waitStatus &lt;= 0)</span><br><span class="line">				s = t;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">if</span> (s != null)</span><br><span class="line">		LockSupport.unpark(s.thread);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>默认唤醒条件队列从头节点开始往后找到的第一个处于非取消状态的节点<br>把其加入同步队列，并更改状态<br>如果更改失败说明这其间该节点被取消了，则返回失败继续往后寻找节点唤醒<br>如果更改成功，则判断同步队列的前驱节点的状态，如果该节点被取消了则唤醒当前新加入的线程53<br>原因是进入同步队列时，只有作为头节点才会立即请求资源<br>否则，同步队列里只有释放资源时才会再次Unpark同步队列下一个线程<br>因此防止前面的节点未获取到资源就取消导致后续没有调起下一个Unpark<br>最好最安全的方法是如果前驱节点突然取消了，unPark一下<br>这样即使还有别的线程在占用资源，他也会在获取资源失败后再次进入park</p>
<h3 id="AQS中的实现"><a href="#AQS中的实现" class="headerlink" title="AQS中的实现"></a>AQS中的实现</h3><p>添加节点，默认添加到尾部<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">private Node addWaiter(Node mode) &#123;</span><br><span class="line">        Node node = new Node(Thread.currentThread(), mode);</span><br><span class="line">        // Try the fast path of enq; backup to full enq on failure</span><br><span class="line">        Node pred = tail;</span><br><span class="line">        <span class="keyword">if</span> (pred != null) &#123;</span><br><span class="line">            node.prev = pred;</span><br><span class="line">            <span class="keyword">if</span> (compareAndSetTail(pred, node)) &#123;</span><br><span class="line">                pred.next = node;</span><br><span class="line">                <span class="built_in">return</span> node;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        enq(node);</span><br><span class="line">        <span class="built_in">return</span> node;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure></p>
<p>条件队列的移除上面已经分析了，那同步队列的呢?</p>
<p>现在我们回到一开始await被signal唤醒后自旋请求资源的地方来看请求资源的方法</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br></pre></td><td class="code"><pre><span class="line">final boolean acquireQueued(final Node node, int arg) &#123;</span><br><span class="line">        boolean failed = <span class="literal">true</span>;</span><br><span class="line">        try &#123;</span><br><span class="line">            boolean interrupted = <span class="literal">false</span>;</span><br><span class="line">            <span class="keyword">for</span> (;;) &#123;</span><br><span class="line">                final Node p = node.predecessor();</span><br><span class="line">                <span class="keyword">if</span> (p == head &amp;&amp; tryAcquire(arg)) &#123;</span><br><span class="line">                    setHead(node);</span><br><span class="line">                    p.next = null; // <span class="built_in">help</span> GC</span><br><span class="line">                    failed = <span class="literal">false</span>;</span><br><span class="line">                    <span class="built_in">return</span> interrupted;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">if</span> (shouldParkAfterFailedAcquire(p, node) &amp;&amp;</span><br><span class="line">                    parkAndCheckInterrupt())</span><br><span class="line">                    interrupted = <span class="literal">true</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; finally &#123;</span><br><span class="line">            <span class="keyword">if</span> (failed)</span><br><span class="line">                cancelAcquire(node);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">private void cancelAcquire(Node node) &#123;</span><br><span class="line">        // Ignore <span class="keyword">if</span> node doesn<span class="string">'t exist</span></span><br><span class="line"><span class="string">        if (node == null)</span></span><br><span class="line"><span class="string">            return;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">        node.thread = null;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">        // Skip cancelled predecessors</span></span><br><span class="line"><span class="string">        Node pred = node.prev;</span></span><br><span class="line"><span class="string">        while (pred.waitStatus &gt; 0)</span></span><br><span class="line"><span class="string">            node.prev = pred = pred.prev;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">        // predNext is the apparent node to unsplice. CASes below will</span></span><br><span class="line"><span class="string">        // fail if not, in which case, we lost race vs another cancel</span></span><br><span class="line"><span class="string">        // or signal, so no further action is necessary.</span></span><br><span class="line"><span class="string">        Node predNext = pred.next;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">        // Can use unconditional write instead of CAS here.</span></span><br><span class="line"><span class="string">        // After this atomic step, other Nodes can skip past us.</span></span><br><span class="line"><span class="string">        // Before, we are free of interference from other threads.</span></span><br><span class="line"><span class="string">        node.waitStatus = Node.CANCELLED;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">        // If we are the tail, remove ourselves.</span></span><br><span class="line"><span class="string">        if (node == tail &amp;&amp; compareAndSetTail(node, pred)) &#123;</span></span><br><span class="line"><span class="string">            compareAndSetNext(pred, predNext, null);</span></span><br><span class="line"><span class="string">        &#125; else &#123;</span></span><br><span class="line"><span class="string">            // If successor needs signal, try to set pred'</span>s next-link</span><br><span class="line">            // so it will get one. Otherwise wake it up to propagate.</span><br><span class="line">            int ws;</span><br><span class="line">            <span class="keyword">if</span> (pred != head &amp;&amp;</span><br><span class="line">                ((ws = pred.waitStatus) == Node.SIGNAL ||</span><br><span class="line">                 (ws &lt;= 0 &amp;&amp; compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &amp;&amp;</span><br><span class="line">                pred.thread != null) &#123;</span><br><span class="line">                Node next = node.next;</span><br><span class="line">                <span class="keyword">if</span> (next != null &amp;&amp; next.waitStatus &lt;= 0)</span><br><span class="line">                    compareAndSetNext(pred, predNext, next);</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                unparkSuccessor(node);</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            node.next = node; // <span class="built_in">help</span> GC</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">	 final Node predecessor() throws NullPointerException &#123;</span><br><span class="line">            Node p = prev;</span><br><span class="line">            <span class="keyword">if</span> (p == null)</span><br><span class="line">                throw new NullPointerException();</span><br><span class="line">            <span class="keyword">else</span></span><br><span class="line">                <span class="built_in">return</span> p;</span><br><span class="line">        &#125;</span><br><span class="line">	//---默认Sync使用不公平，此处作为示例	</span><br><span class="line">	final boolean nonfairTryAcquire(int acquires) &#123;</span><br><span class="line">            final Thread current = Thread.currentThread();</span><br><span class="line">            int c = getState();</span><br><span class="line">            <span class="keyword">if</span> (c == 0) &#123;</span><br><span class="line">                <span class="keyword">if</span> (compareAndSetState(0, acquires)) &#123;</span><br><span class="line">                    setExclusiveOwnerThread(current);</span><br><span class="line">                    <span class="built_in">return</span> <span class="literal">true</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span> <span class="keyword">if</span> (current == getExclusiveOwnerThread()) &#123;</span><br><span class="line">                int nextc = c + acquires;</span><br><span class="line">                <span class="keyword">if</span> (nextc &lt; 0) // overflow</span><br><span class="line">                    throw new Error(<span class="string">"Maximum lock count exceeded"</span>);</span><br><span class="line">                setState(nextc);</span><br><span class="line">                <span class="built_in">return</span> <span class="literal">true</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="built_in">return</span> <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br></pre></td></tr></table></figure>
<p>当请求资源时什么情况执行finally<br>1.前驱节点为null，空指针异常failed变量为初始值true，此时取消资源会把自己移除出同步队列（因为头指针是特殊标记，不代表实际请求资源的Node）<br>    —在插入同步队列时，如果没有头指针会自动初始化一个头指针，所以第一个插入的节点不会有问题<br>2.该节点的前驱节点是头节点，则当前结点获取到资源，并把自己设置为头指针，failed变量标记为false（因为新的头指针不需要删除，这样就把旧的头节点出队了）<br>3.超出资源限制的请求数量，throw new Error(“Maximum lock count exceeded”)，取消该node<br>cancelAcquire方法会将当前结点标记为取消状态，并且迭代移除当前结点的已取消的前驱节点知道第一个非取消状态的节点<br>主要操作是<br>1.当前是尾节点，删除当前结点更新尾节点<br>2.前驱节点不是头节点（因为头节点是标记节点要特殊处理），删除当前结点<br>3.前驱节点是头节点，调用unParkSuccess去唤起后一个线程（因为他没有获取到资源又是第一个节点不执行release）</p>
<p>而被标记为取消的节点在shouldParkAfterFailedAcquire中会被删除<br>因为Park下一个节点，他不是head下的第一个节点所以他会请求失败并执行shouldParkAfterFailedAcquire<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) &#123;</span><br><span class="line">        int ws = pred.waitStatus;</span><br><span class="line">        <span class="keyword">if</span> (ws == Node.SIGNAL)</span><br><span class="line">            /*</span><br><span class="line">             * This node has already <span class="built_in">set</span> status asking a release</span><br><span class="line">             * to signal it, so it can safely park.</span><br><span class="line">             */</span><br><span class="line">            <span class="built_in">return</span> <span class="literal">true</span>;</span><br><span class="line">        <span class="keyword">if</span> (ws &gt; 0) &#123;</span><br><span class="line">            /*</span><br><span class="line">             * Predecessor was cancelled. Skip over predecessors and</span><br><span class="line">             * indicate retry.</span><br><span class="line">             */</span><br><span class="line">            <span class="keyword">do</span> &#123;</span><br><span class="line">                node.prev = pred = pred.prev;</span><br><span class="line">            &#125; <span class="keyword">while</span> (pred.waitStatus &gt; 0);</span><br><span class="line">            pred.next = node;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            /*</span><br><span class="line">             * waitStatus must be 0 or PROPAGATE.  Indicate that we</span><br><span class="line">             * need a signal, but don<span class="string">'t park yet.  Caller will need to</span></span><br><span class="line"><span class="string">             * retry to make sure it cannot acquire before parking.</span></span><br><span class="line"><span class="string">             */</span></span><br><span class="line"><span class="string">            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);</span></span><br><span class="line"><span class="string">        &#125;</span></span><br><span class="line"><span class="string">        return false;</span></span><br><span class="line"><span class="string">    &#125;</span></span><br></pre></td></tr></table></figure></p>
<h3 id="请移步"><a href="#请移步" class="headerlink" title="请移步"></a>请移步</h3><p>个人主页: <a href="http://yangyitao.top" target="_blank" rel="noopener">yangyitao.top</a></p>

      
    </div>
    
  </div>
  
    
<nav id="article-nav">
  
    <a href="/blog/2019/03/30/GC与垃圾回收分代/" id="article-nav-newer" class="article-nav-link-wrap">
      <strong class="article-nav-caption">&lt;</strong>
      <div class="article-nav-title">
        
          GC与垃圾回收分代
        
      </div>
    </a>
  
  
    <a href="/blog/2019/03/24/并发基石-Markword与锁升级/" id="article-nav-older" class="article-nav-link-wrap">
      <div class="article-nav-title">并发基石-Markword与锁升级</div>
      <strong class="article-nav-caption">&gt;</strong>
    </a>
  
</nav>

  
</article>


<div class="ds-share share" data-thread-key="并发基石-AQS与Condition" data-title="并发基石-AQS与Condition" data-url="http://eetal.gitee.io/blog/blog/2019/03/26/并发基石-AQS与Condition/"  data-images="/blog/images/head.jpg" data-content="并发基石-AQS与Condition">
    <div class="ds-share-inline">
      <ul  class="ds-share-icons-16">
      	<li data-toggle="ds-share-icons-more"><a class="ds-more" href="javascript:void(0);">分享到：</a></li>
        <li><a class="ds-weibo" href="javascript:void(0);" data-service="weibo">微博</a></li>
        <li><a class="ds-qzone" href="javascript:void(0);" data-service="qzone">QQ空间</a></li>
        <li><a class="ds-qqt" href="javascript:void(0);" data-service="qqt">腾讯微博</a></li>
        <li><a class="ds-wechat" href="javascript:void(0);" data-service="wechat">微信</a></li>
      </ul>
      <div class="ds-share-icons-more">
      </div>
    </div>
 </div>
 





</div>
      <footer id="footer">
  <div class="outer">
    <div id="footer-info">
      <div class="footer-left">
        &copy; 2019 Eetal
      </div>
        <div class="footer-right">
          <a href="http://hexo.io/" target="_blank">Hexo</a>  Theme <a href="https://github.com/smackgg/hexo-theme-smackdown" target="_blank">Smackdown</a>
        </div>
    </div>
  </div>
</footer>
    </div>
    
  <link rel="stylesheet" href="/blog/fancybox/jquery.fancybox.css">


<script>
	var yiliaConfig = {
		fancybox: true,
		mathjax: true,
		animate: true,
		isHome: false,
		isPost: true,
		isArchive: false,
		isTag: false,
		isCategory: false,
		open_in_new: false
	}
</script>
<script src="/blog/js/main.js"></script>



<script type="text/x-mathjax-config">
MathJax.Hub.Config({
    tex2jax: {
        inlineMath: [ ['$','$'], ["\\(","\\)"]  ],
        processEscapes: true,
        skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
    }
});

MathJax.Hub.Queue(function() {
    var all = MathJax.Hub.getAllJax(), i;
    for(i=0; i < all.length; i += 1) {
        all[i].SourceElement().parentNode.className += ' has-jax';                 
    }       
});
</script>

<script src="//cdn.bootcss.com/mathjax/2.7.0/MathJax.js"></script>


  </div>
</body>
</html>